﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Reflection;

namespace Singer.Framework.LocalEventBus;

/// <summary>
/// 本地事件总线 服务拓展
/// </summary>
public static class LocalEventBusServiceExtensions
{
    /// <summary>
    /// 注册事件总线
    /// 将整个程序集中带有EventHandler特性的事件处理程序类都注册到事件总线中
    /// <param name="handlerAssembly">事件处理程序所在的程序集</param>
    /// </summary>
    public static void AddLocalEventBus(this IServiceCollection services, Assembly handlerAssembly)
    {
        var handlerTypes = handlerAssembly.GetTypes().Where(x => x.GetCustomAttribute<LocalEventHandlerAttribute>() != null);
        Dictionary<Type, List<LocalEventHandlerModel>> handlerDic = new();
        foreach (Type handlerType in handlerTypes)
        {
            services.Replace(new ServiceDescriptor(handlerType, handlerType, ServiceLifetime.Scoped)); // 将事件处理程序注入到容器中，这样事件处理程序也可以像普通服务一样使用依赖注入
            var attribute = handlerType.GetCustomAttribute<LocalEventHandlerAttribute>();
            if (attribute == null)
                continue;
            /*
            var handlerDelegateType = typeof(Action<,>).MakeGenericType(typeof(object), attribute.MessageType);// 委托类型 Action<object, TEventArgs>
            MethodInfo? eventHandlerMethod = handlerType.GetMethod("OnEventHandler"); // void OnEventHandler(object e, TEventArgs args)
            if (eventHandlerMethod == null)
                continue;
            var handlerDelegate = Delegate.CreateDelegate(handlerDelegateType, null, eventHandlerMethod);
            */
            var handlerModel = new LocalEventHandlerModel() { Sort = attribute.Sort, HandlerType = handlerType };
            if (handlerDic.ContainsKey(attribute.MessageType))
            {
                handlerDic[attribute.MessageType].Add(handlerModel);
            }
            else
            {
                handlerDic.Add(attribute.MessageType, new List<LocalEventHandlerModel>() { handlerModel });
            }
        }
        LocalEventBus? eventBus = services.BuildServiceProvider().GetService<ILocalEventBus>() as LocalEventBus; // 此方法可能多次调用，单例处理

        services.AddHttpContextAccessor(); // 依赖Http上下文，通过HttpContext拿到每次事件触发时的 服务作用域
        services.AddSingleton<ILocalEventBus, LocalEventBus>(sp => // 将事件总线 注册为 单例服务
        {
            IHttpContextAccessor httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
            eventBus = eventBus ?? new LocalEventBus(httpContextAccessor);
            eventBus.AddHandlers(handlerDic); // 将解析出来的事件处理程序添加到事件总线中
            return eventBus;
        });
    }
}
